﻿using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace KinonekoSoftware.Extensions.Collections
{
    public class ObservableStack<T> : IEnumerable<T>, IEnumerable, ICollection, IReadOnlyCollection<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        private readonly Stack<T>                            _impl;
        private          PropertyChangedEventHandler         PropertyChangedField;
        private          NotifyCollectionChangedEventHandler CollectionChangedField;

        public ObservableStack()
        {
            _impl = new Stack<T>();
        }

        public ObservableStack(int capacity)
        {
            _impl = new Stack<T>(capacity);
        }

        public ObservableStack(IEnumerable<T> collection)
        {
            _impl = new Stack<T>(collection);
        }

        private void NotifyChanged()
        {
            
            //
            //
            PropertyChangedField?.Invoke(this, CollectionStatic.CountPropertyChanged);
            PropertyChangedField?.Invoke(this, CollectionStatic.IndexerPropertyChanged);

            //
            //
            CollectionChangedField?.Invoke(this, CollectionStatic.ResetCollectionChanged);
        }
        


        public void Clear()
        {
            _impl.Clear();
        }

        public bool Contains(T item) => _impl.Contains(item);


        public void CopyTo(T[] array, int arrayIndex)
        {
            _impl.CopyTo(array, arrayIndex);
        }

        void ICollection.CopyTo(Array array, int arrayIndex)
        {

            ((ICollection)_impl).CopyTo(array, arrayIndex);
        }

        public Stack<T>.Enumerator GetEnumerator() => _impl.GetEnumerator();


        IEnumerator<T> IEnumerable<T>.GetEnumerator() => _impl.GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => _impl.GetEnumerator();

        public void TrimExcess()
        {
            _impl.TrimExcess();
        }


        public T Peek() => _impl.Peek();


        public bool TryPeek([MaybeNullWhen(false)] out T result) => _impl.TryPeek(out result);

        public T Pop()
        {
            var item = _impl.Pop();

            NotifyChanged();
            return item;
        }

        
        public bool TryPop([MaybeNullWhen(false)] out T result)
        {
            var r = _impl.TryPop(out result);
            NotifyChanged();
            return r;
        }

        
        public void Push(T item)
        {
            _impl.Push(item);
            NotifyChanged();
        }


        
        public int EnsureCapacity(int capacity)
        {
            return _impl.EnsureCapacity(capacity);
        }
        
        public T[] ToArray() => _impl.ToArray();

        
        
        public int Count => _impl.Count;


        bool ICollection.IsSynchronized => ((ICollection)_impl).IsSynchronized;


        object ICollection.SyncRoot => (object)this;
        
        public event PropertyChangedEventHandler PropertyChanged
        {
            add => PropertyChangedField += value;
            remove => PropertyChangedField -= value;
        }
        
        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add => CollectionChangedField += value;
            remove => CollectionChangedField -= value;
        }
    }
}